const webpack = require("webpack");
const path = require("path");
const MFS = require("memory-fs");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");
const serverConstant = require("../configs/serverConstant");
const clientConfig = require("../configs/webpack.config.client");
const serverConfig = require("../configs/webpack.config.server");
const readFile = (fs, fileName) => fs.readFileSync(path.join(clientConfig.output.path, fileName), "utf-8");
module.exports = function devCompiler(app, callback, onCompilingStart, onCompilingStop) {
	return new Promise((resolve, reject) => {
		/**注册回调开始 */
		let serverDevBundleResolve, clientManifestResolve;
		const update = (serverDevBundle, clientManifest) => {
			callback(serverDevBundle, clientManifest);
			if (serverDevBundleResolve && clientManifestResolve) {
				resolve();
				onCompilingStop();
			}
		};
		/**注册回调结束 */
		const mfs = new MFS();
		/**客户端打包开始 */
		const clientCompiler = webpack(clientConfig);
		clientCompiler.hooks.compilation.tap("devCompilerClientCompilation", compilation => {
			console.debug("客户端编译更新...");
			clientManifestResolve = false;
			onCompilingStart();
		});
		// 使用 webpack-dev-middleware 中间件服务 webpack 打包后的资源文件
		const devMiddleware = webpackDevMiddleware(clientCompiler, { publicPath: clientConfig.output.publicPath });
		// , outputFileSystem: mfs
		app.use(devMiddleware);
		// 热更新中间件
		app.use(webpackHotMiddleware(clientCompiler, { reload: true }));
		// TS 检查出问题时
		// const ForkTsCheckerWebpackPluginHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(clientCompiler);
		// let cachedStats;
		// const calledIssues = new Set();
		// ForkTsCheckerWebpackPluginHooks.issues.tap("devCompilerFTConIssues", (issues, compilation) => {
		// 	if (cachedStats) {
		// 		try {
		// 			const issuesStr = JSON.stringify(issues);
		// 			if (calledIssues.has(issuesStr)) {
		// 				calledIssues.delete(issuesStr);
		// 			} else {
		// 				calledIssues.add(issuesStr);
		// 				clientCompiler.hooks.done.callAsync(
		// 					Object.assign(cachedStats, {
		// 						triggerByFTC: true,
		// 						toJson() {
		// 							return {
		// 								hash: cachedStats.hash,
		// 								time: cachedStats.endTime - cachedStats.startTime,
		// 								warnings: [],
		// 								errors: getLogList(issues),
		// 								modules: [],
		// 							};
		// 						},
		// 					}),
		// 					console.error
		// 				);
		// 			}
		// 		} catch (e) {
		// 			console.error(e);
		// 		}
		// 	}
		// 	return issues;
		// });
		// 打包完成时进行更新
		clientCompiler.hooks.done.tap("devCompilerClientDone", stats => {
			if (stats.triggerByFTC) return console.debug("triggerByFTC, skip");
			if (!serverConstant.checkArgv("code1st")) cachedStats = stats;
			const info = stats.toJson();
			if (stats.hasWarnings()) console.warn("客户端编译警告", info.warnings.join("\n"));
			if (stats.hasErrors()) return console.error("客户端编译异常:", info.errors.length);
			console.debug(`[${stats.endTime - stats.startTime}]ms 客户端编译完成, warnings: [${info.warnings.length}]`);
			// 从 webpack-dev-middleware 中间件存储的内存中读取打包后的文件
			const clientManifest = readFile(devMiddleware.context.outputFileSystem, "client-manifest.json");
			// console.log("clientManifest", clientManifest);
			clientManifestResolve = true;
			update(null, clientManifest);
		});
		/**客户端打包结束 */

		/**服务端打包开始 */
		const serverCompiler = webpack(serverConfig);
		// 使用内存文件系统
		
		serverCompiler.outputFileSystem = mfs;
		// 监视服务端打包入口文件，有更改就更新
		serverCompiler.hooks.compilation.tap("devCompilerServerCompilation", compilation => {
			console.debug("服务端编译更新...");
			serverDevBundleResolve = false;
			onCompilingStart();
		});
		serverCompiler.watch({}, (err, stats) => {
			const info = stats.toJson();
			if (stats.hasWarnings()) console.warn("服务端编译警告", info.warnings.filter(str => !/node_modules[/]encoding[/]lib[/]iconv-loader.js/.test(str)).join("\n"));
			if (stats.hasErrors()) console.error("服务端编译异常:", info.errors.length);
			console.debug(`[${stats.endTime - stats.startTime}ms] 服务端编译完成, warnings: [${info.warnings.length}]`);
			const serverDevBundle = readFile(mfs, serverCompiler.options.output.filename);
			serverDevBundleResolve = true;
			update(serverDevBundle, null);
		});
		/**服务端打包结束 */
	});
};
